package com.micro.magupe.sharding.statement;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.List;

import com.micro.magupe.sharding.connection.ShardingConnection;
import com.micro.magupe.sharding.executor.StatementExecutor;
import com.micro.magupe.sharding.merge.result.IteratorStreamMergedResult;
import com.micro.magupe.sharding.merge.result.MergedResult;
import com.micro.magupe.sharding.merge.result.QueryResult;
import com.micro.magupe.sharding.resultset.ShardingResultSet;
import com.micro.magupe.sharding.router.SQLRouterResult;
import com.micro.magupe.sharding.router.SQLRouterUnit;
import com.micro.magupe.sharding.rule.ShardingRule;
import com.micro.magupe.sharding.rule.ShardingTableRule;

public class ShardingStatement extends AbstractStatement{

	private final ShardingConnection connection;
	
	private SQLRouterResult routerResult;
	
	private final StatementExecutor statementExecutor;
	
	private ResultSet currentResultSet;
	
    public ShardingStatement(final ShardingConnection connection) {
        this(connection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }
    
    public ShardingStatement(final ShardingConnection connection, final int resultSetType, final int resultSetConcurrency) {
        this(connection, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
    }
    
    public ShardingStatement(final ShardingConnection connection, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) {
        this.connection = connection;
        statementExecutor = new StatementExecutor(connection, resultSetType);
    }
    
	public SQLRouterResult getRouterResult() {
		return routerResult;
	}
	
	public ShardingConnection getConnection() {
		return connection;
	}
	
    @Override
    public Collection<Statement> getRoutedStatements() {
        return statementExecutor.getStatements();
    }
	
	@Override
	public ResultSet executeQuery(String sql) throws SQLException {
		ResultSet result;
		try {
			clearPrevious();
	        sqlRoute(sql);
	        statementExecutor.init(routerResult);
	        // ResultSet封装进入StreamQueryResult（实现QueryResult接口）对象中
	        List<QueryResult> queryResults = statementExecutor.executeQuery();
	        // 原始的ResultSet集合
	        List<ResultSet> resultSets = statementExecutor.getResultSets();
	        MergedResult mergedResult = new IteratorStreamMergedResult(queryResults);
	        result = new ShardingResultSet(resultSets, mergedResult, this);
		} finally {
            currentResultSet = null;
        }
		
        currentResultSet = result;
        
		return result;
	}
	
	@Override
	public boolean execute(String sql) throws SQLException {
		return false;
	}

	@Override
	public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
		return false;
	}

	@Override
	public boolean execute(String sql, int[] columnIndexes) throws SQLException {
		return false;
	}

	@Override
	public boolean execute(String sql, String[] columnNames) throws SQLException {
		return false;
	}
	
	@Override
	public int executeUpdate(String sql) throws SQLException {
		return 0;
	}

	@Override
	public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
		return 0;
	}

	@Override
	public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
		return 0;
	}

	@Override
	public int executeUpdate(String sql, String[] columnNames) throws SQLException {
		return 0;
	}

	@Override
	public ResultSet getResultSet() throws SQLException {
        if (null != currentResultSet) {
            return currentResultSet;
        }
        
		return null;
	}
	
	@Override
	public int getResultSetType() throws SQLException {
		return statementExecutor.getResultSetType();
	}
	
	@Override
	public int getResultSetConcurrency() throws SQLException {
		return 0;
	}

	@Override
	public int getResultSetHoldability() throws SQLException {
		return 0;
	}
	
	@Override
	public ResultSet getGeneratedKeys() throws SQLException {
		return null;
	}

	private void clearPrevious() {
		
	}
	
	private void sqlRoute(final String sql) {
		routerResult = new SQLRouterResult(null);
		
		ShardingRule rule = getConnection().getRule();
		List<String> dbs = rule.getDbs();
		List<ShardingTableRule> tableRules = rule.getTableRules();
		dbs.forEach((db) -> {
			ShardingTableRule tableRule = tableRules.get(0);
			int start = Integer.valueOf(tableRule.getCounts().substring(0, 1));
			int end = Integer.valueOf(tableRule.getCounts().substring(2, 3));
			for (int i = start; i <= end; i++) {
				routerResult.getRouterUnits().add(new SQLRouterUnit(db, sql + i));
			}
		});
	}
}
